#include "StdAfx.h"
#include "AuthCrypt.h"
#include "AuthClient.h"
#include "RealmHandler.h"

ListenServer* AuthClient::gClientServer = NULL;
SocketManager<AuthClient>* AuthClient::gClientMgr = new SocketManager<AuthClient>();

AuthClient::AuthClient() : mCrypt(this), mChlgPassed(false) {
	mUseDirectNotify = true;
	mPacketHandlers[Challenge] = std::tr1::bind(&AuthCrypt::handleAuthChallange, &mCrypt, std::tr1::placeholders::_1);
	mPacketHandlers[Proof] = std::tr1::bind(&AuthCrypt::handleAuthProof, &mCrypt, std::tr1::placeholders::_1);
	mPacketHandlers[ReconnectChallenge] = std::tr1::bind(&AuthCrypt::handleReconnectChlg, &mCrypt, std::tr1::placeholders::_1);
	mPacketHandlers[ListRealms] = std::tr1::bind(&AuthClient::handleRealmList, this, std::tr1::placeholders::_1);
}

void AuthClient::startNetwork() {
	sLog.outNotice("Network", "Starting sockets...");
	gClientServer = new ListenServer(Configs::logon().getUInt32("network", "bindport"), Configs::logon().getString("network", "bindaddress"));
	gClientServer->setEventListener(gClientMgr);
	
	sThreadPool.executeTask(gClientServer);
	sThreadPool.executeTask(gClientMgr);
	sLog.outNotice("Network", "Threads launched, ready for connections!");
}

void AuthClient::stopNetwork() {
	sLog.notice("Network") << "Shutting down sockets..." << std::endl;
	gClientServer->terminate();
}

void AuthClient::clientConnected(Socket* client) {
	mSocket = client;
	sLog.notice("Network") << "Client connected from '" << mSocket->getRemotePoint().toString() << "'." << std::endl;
}

void AuthClient::notifyDataRead(const std::vector<uint8>& data) {
	ByteBuffer bb(data);
	uint8 opcode;
	bb >> opcode;
	sLog.notice("AuthClient") << "Packet: " << (uint32)opcode << std::endl;
	if(mPacketHandlers.find(opcode) != mPacketHandlers.end())
		mPacketHandlers[opcode](bb);
}

void AuthClient::handleRealmList(ByteBuffer& buffer) {
	if(mCrypt.hasAuthPassed() == false) {
		mSocket->disconnect();
		return;
	}

	ByteBuffer resp;
	resp << uint8(0x10) << uint16(0) << uint32(0);
	sRealmHandler.addRealms(resp);
	resp << uint8(0x17) << uint8(0);

	resp.set(uint16(resp.getBuffer().size() - 3), 1);

	sendData(resp);
}